package com.aleyn.processor.data

import com.google.devtools.ksp.symbol.KSDeclaration
import kotlin.reflect.KClass

/**
 * @author: Aleyn
 * @date: 2023/7/27 16:17
 *
 * 这个文件定义了用于在编译期描述和存储依赖注入信息的元数据类。
 * 这些数据类和密封类共同构成了一个模型，用于表示如何创建和注入一个类的实例。
 */

/**
 * 代表一个依赖注入的 "定义注解" (Definition Annotation)。
 *
 * 例如 `@Single` 或 `@Factory` 这样的注解，它们标记了一个类应该如何被容器管理。
 *
 * @property keyword 关键字，通常是注解的类名，用于唯一标识。
 * @property annotationType 注解的 KClass 类型。
 */
data class DefinitionAnnotation(
    val keyword: String,
    val annotationType: KClass<*>
) {
    /**
     * 注解的简单名称，例如 "Single"。
     */
    val annotationName = annotationType.simpleName
}

/**
 * 密封类，表示一个依赖的 "定义" (Definition)。
 *
 * 一个 Definition 描述了如何创建一个特定类的实例，包括它的构造函数参数、包名、作用域等信息。
 * 它是代码生成阶段的核心数据模型。
 *
 * @property label 标识符，通常是类的完全限定名。
 * @property parameters 构造函数参数列表。
 * @property packageName 类所在的包名。
 * @property qualifier 用于区分同一类型的不同实例的限定符。
 * @property lazy 是否延迟初始化。
 * @property keyword 使用的定义注解 (例如 `@Single`)。
 * @property binding 如果这个定义是绑定到某个接口的，这里会持有该接口的声明。
 */
sealed class Definition(
    val label: String,
    val parameters: List<ConstructorParameter>,
    val packageName: String,
    val qualifier: String? = null,
    val lazy: Boolean? = null,
    val keyword: DefinitionAnnotation,
    val binding: KSDeclaration?
) {

    /**
     * 检查当前定义的类型是否与给定的定义注解匹配。
     */
    fun isType(keyword: DefinitionAnnotation): Boolean = this.keyword == keyword

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as Definition

        if (label != other.label) return false
        if (packageName != other.packageName) return false

        return true
    }

    override fun hashCode(): Int {
        var result = label.hashCode()
        result = 31 * result + packageName.hashCode()
        return result
    }

    override fun toString(): String {
        return "label:$label," +
                "parameters:$parameters," +
                "packageName:$packageName," +
                "qualifier:$qualifier," +
                "isCreatedAtStart:$lazy," +
                "keyword：${keyword}," +
                "bindings:$binding"
    }

    /**
     * 表示一个基于类的定义。
     *
     * 这是 [Definition] 最常见的子类型，代表一个普通的类实例。
     *
     * @param className 类的完全限定名。
     * @param constructorParameters 构造函数参数列表。
     */
    class ClassDefinition(
        packageName: String,
        qualifier: String?,
        lazy: Boolean? = null,
        keyword: DefinitionAnnotation,
        className: String,
        constructorParameters: List<ConstructorParameter> = emptyList(),
        binding: KSDeclaration?
    ) : Definition(
        className,
        constructorParameters,
        packageName,
        qualifier,
        lazy,
        keyword,
        binding
    )


}

/**
 * 密封类，表示构造函数中的一个参数。
 *
 * @property nullable 参数是否可空。
 */
sealed class ConstructorParameter(val nullable: Boolean = false) {

    /**
     * 表示一个需要从依赖注入容器中获取的 "依赖" 参数。
     *
     * @param value 依赖的限定符 (qualifier)。
     * @param isNullable 依赖是否可空。
     * @param kind 依赖的类型 (单个实例或列表)。
     */
    data class Dependency(
        val value: String? = null,
        val isNullable: Boolean = false,
        val kind: DependencyKind = DependencyKind.Single
    ) : ConstructorParameter(isNullable)

    /**
     * 表示一个需要从外部（例如 Activity 的 Intent）注入的 "参数"。
     *
     * 这通常用于 `@Autowired` 场景，参数值由路由框架在导航时传递。
     */
    data class ParameterInject(val isNullable: Boolean = false) : ConstructorParameter(isNullable)
}

/**
 * 枚举，表示依赖的种类。
 */
enum class DependencyKind {
    /**
     * 单个实例依赖。
     */
    Single,

    /**
     * 列表实例依赖 (例如 `List<MyInterface>`)。
     */
    List
}